package storage;

import Interface.Entity;

/**
 * Developed for NTT - All is an EntityStorage
 * Generatore di query
 * @author Alessandro Pollace
 * @version 0.1
 */
public class QueryGenerator {

    /***** METHOD - PRIVATE *****/
    /**
     * Permette di serializzare i nomi degli attributi modificati dall'ultima
     * lettura o salvataggio modifica
     *
     * @param e
     *            entity di cui si intende serializzare i nomi degli attributi
     * @return nomi degli attributi modificati dall'ultima lettura o salvataggio
     *         modifica separati da una virgola
     * @throws Exception
     */
    private String serializeCombinationNameValueModified(Entity e)
            throws Exception {
        // DATA
        String serialized, name[];
        EntityStorage es = (EntityStorage) e;
        int i;
        // OPERATION
        name = e.getAllNameAttributeModified();
        serialized = name[0] + "='" + es.getAttributeValueNoLimitsToString(name[0])
                + "'";

        for (i = 1; i < name.length; i++) {
            serialized = serialized + "," + name[i] + "='"
                    + es.getAttributeValueNoLimitsToString(name[i]) + "'";
        }
        return serialized;
    }

    /**
     * Permette di serializzare i nomi degli attributi
     *
     * @param e
     *            entity di cui si intende serializzare i nomi degli attributi
     * @return nomi serializzai separati da una virgola
     */
    private String serializeName(Entity e) {
        // DATA
        String serialized, name[];
        int i;
        // OPERATION
        name = e.getAllNameAttribute();
        serialized = name[0];
        for (i = 1; i < name.length; i++) {
            serialized = serialized + "," + name[i];
        }
        return serialized;
    }

    /**
     * Permette di serializzare i valori degli attributi
     *
     * @param e
     *            entity di cui si intende serializzare i valori degli attributi
     * @return valori serializzai separati da una virgola
     * @throws Exception
     *             Metodo ToString non implementato negli attributi dell'entity
     */
    private String serializeValue(Entity e) throws Exception {
        // DATA
        String serialized, name[];
        EntityStorage es = (EntityStorage) e;
        int i;
        // OPERATION
        name = e.getAllNameAttribute();
        try {
            serialized = "'" + es.getAttributeValueNoLimitsToString(name[0]);
            for (i = 1; i < name.length; i++) {
                serialized = serialized + "','"
                        + es.getAttributeValueNoLimitsToString(name[i]);
            }
        } catch (Exception e1) {
            throw new Exception(
                    "Error-QueryGenerator-serializeValue-MethodToStringNotImplemented");
        }
        return serialized + "'";
    }

    /************************************************************************/
    /***** METHOD - PROTECTED *****/
    /**
     * Genera una query di salvataggio per l'entity e
     *
     * @param e
     *            EntityStorage su cui lavorare
     * @throws Exception
     * @return Query
     */
    protected String getQuerySalvataggio(Entity e) {
        // DATA
        String query = null, logicalDelete1, logicalDelete2;
        // OPERATION
        EntityStorage e2 = (EntityStorage) e;
        if (e2.isLogicalDeleteEntity() == true) {
            logicalDelete1 = ", deleted";
            logicalDelete2 = ", 'false'";
        } else {
            logicalDelete1 = "";
            logicalDelete2 = "";
        }

        try {
            query = "INSERT INTO " + e.getNome() + " (" + this.serializeName(e)
                    + logicalDelete1 + ") VALUES ( " + this.serializeValue(e)
                    + logicalDelete2 + ");";
        } catch (Exception ex) {
        }

        return query;
    }

    /**
     * Genera una query di UPDATE per l'entity e
     *
     * @param e
     *            EntityStorage su cui lavorare
     * @return Query
     * @throws Exception
     */
    protected String getQueryModifica(Entity e) {
        // DATA
        String query = null, pk, logicalDelete;
        EntityStorage e2 = (EntityStorage) e;
        // OPERATION
        if (e2.isLogicalDeleteEntity() == true) {
            logicalDelete = " AND deleted = 'false'";
        } else {
            logicalDelete = "";
        }
        try {
            pk = e.getPrymaryKeyName();
            query = "UPDATE " + e.getNome() + " SET "
                    + this.serializeCombinationNameValueModified(e) + " WHERE "
                    + pk + "='" + e2.getAttributeValueNoLimits(pk).toString() + "'"
                    + logicalDelete + ";";
            return query;
        } catch (Exception ex) {
        }

        return query;
    }

    /**
     * Questo metodo genera in qutomatico una query di cancellazione, facendosi
     * carico della differenziazione tra cancellazione logica e fisica
     *
     * @param e
     *            EntityStorage su cui lavorare
     * @return Query
     */
    protected String getQueryCancellazione(Entity e) {
        // DATA
        String query = null, pk;

        // OPERATION
        EntityStorage e2 = (EntityStorage) e;
        pk = e.getPrymaryKeyName();
        try {
            if (e2.isLogicalDeleteEntity() == true) {
                // CANCELLAZIONE LOGICA
                query = "UPDATE " + e.getNome() + "SET (deleted='true')"
                        + ") WHERE " + pk + "'"
                        + e2.getAttributeValueNoLimits(pk).toString() + "';";
            } else {
                // CANCELLAZIONE FISICA
                query = "DELETE FROM " + e.getNome() + "where " + pk + "='"
                        + e2.getAttributeValueNoLimitsToString(pk) + "';";
            }
        } catch (Exception ex) {
        }
        return query;
    }

    /**
     * Questo metodo permette di creare una query per la ricerca di un entity.
     *
     * @param e
     *            EntityStorage su cui lavorare
     * @param parameter
     *            Parametri per la ricerca, è un array: Parametri
     *            momentaneamente non supportati passare NULL per avere la
     *            compatibilità con le versioni successive
     *
     * @return Query
     */
    protected String getQueryRicerca(Entity e, String parameter[]) throws Exception {
        String query = null;
        EntityStorage es = (EntityStorage) e;
        if (parameter[0].equals("allIstance")) {
            query = "SELECT * FROM " + e.getNome() + ";";
        }

        if (parameter[0].equals("find")) {
            String paramTMP[] = e.getAllNameAttributeModified();
            query = paramTMP[0] + " LIKE '%" + es.getAttributeValueNoLimitsToString(paramTMP[0]) + "%'";
            for (int i = 1; i < paramTMP.length; i++) {
                query = query + " OR " + paramTMP[i] + " LIKE '%" + es.getAttributeValueNoLimitsToString(paramTMP[i]) + "%'";
            }
            query = "SELECT * FROM " + e.getNome() + " WHERE " + query + ";";
        }

        if (parameter[0].equals("onlyOne")) {
            query = "SELECT * FROM " + e.getNome() + " WHERE " + parameter[1] + " = '" + parameter[2] + "';";
        }
        return query;
    }

    /**
     * Questo metodo genera una query di caricamento di una entity
     *
     * @param e
     *            EntityStorage su cui lavorare
     * @return Query
     * @throws Exception
     */
    protected String getQueryCaricamento(Entity e) throws Exception {
        // DATA
        String query = null, pk, logicalDelete;
        String pkValue;
        EntityStorage es = (EntityStorage) e;
        // OPERATION
        EntityStorage e2 = (EntityStorage) e;
        pk = e.getPrymaryKeyName();
        pkValue = es.getAttributeValueNoLimitsToString(pk);
        if (pkValue == null) {
            throw new Exception(
                    "Error-QueryGenerator-getQueryCaricamento-NotInitializedPrimaryKey");
        }
        if (e2.isLogicalDeleteEntity() == true) {
            logicalDelete = " AND deleted = 'false'";
        } else {
            logicalDelete = "";
        }
        try {
            query = "SELECT " + this.serializeName(e) + " FROM " + e.getNome()
                    + " WHERE " + pk + "='" + pkValue + "'" + logicalDelete
                    + ";";
        } catch (Exception ex) {
        }

        return query;
    }

    /**
     * Questo metodo legge la configurazione di un entity e crea la query adatta
     * per la creazione della tabella sul database
     *
     * @param entityName
     *            Nome dell'entity di cui si intende creare la tabella
     * @return Query
     * @throws Exception
     */
    protected String getQueryCreateTable(Entity e) throws Exception {
        // DATA
        String name[], type, query = null, forced, query2 = null;
        TypeConverter converter;
        // OPERATION
        converter = new TypeConverter();
        name = e.getAllNameAttribute();

        for (int i = 0; i < name.length; i++) {
            type = converter.NTTToDatabase(e.getAttributeType(name[i]));
            if (e.getAttributeIsInserible(name[i]).equals("FORCED") == true) {
                forced = " NOT NULL";
            } else {
                forced = "";
            }
            if (query == null) {
                query = "'" + name[i] + "' " + type + forced;
            } else {
                query = query + ", '" + name[i] + "' " + type + forced;
            }

        }
        // Query creazione tabella
        query = "CREATE TABLE '" + e.getNome() + "' (" + query + ");";

        //Query di creazione indici unici
        for (int i = 0; i < name.length; i++) {
            if (e.getAttributeIsUnique(name[i]) == true) {
                if (query2 == null) {
                    query2 = "CREATE UNIQUE INDEX '" + name[i] + "' ON "
                            + e.getNome() + " ( " + name[i] + " ASC);";
                } else {
                    query2 = query2 + "CREATE UNIQUE INDEX '" + name[i] + "' ON "
                            + e.getNome() + " ( " + name[i] + " ASC);";
                }

            }
        }

        return query + query2;
    }
    /************************************************************************/
}
